//Documentation complete
/**
 * @author Jeff
 * @version 2009AP05
 */

package control;

import broker.*;
import problemDomain.*;
import static problemDomain.ErrorBean.*;
import static problemDomain.ErrorBean.ErrorCode.*;

import java.util.*;

/**
 * Control object for food orders object operations.
 */
public class OrderControl extends Control {
	
	/* Attributes */
	
	private OrderBroker ob;
	private MenuItemBroker mib;
	private PatronAccountBroker pab;
	private DeliveryBroker db;
	private ConfigFileBroker cfb;
	
	/* END Attributes */
	
	
	/* Constructors */
	
	/**
	 * Constructs an <code>OrderControl</code>.
	 * @throws ErrorBean if the database is not available
	 */
	public OrderControl () throws ErrorBean {
		ob = OrderBroker.getBroker();
		mib = MenuItemBroker.getBroker();
		pab = PatronAccountBroker.getBroker();
		db = DeliveryBroker.getBroker();
		cfb = ConfigFileBroker.getBroker();
	}
	
	/* END Constructors */
	
	
	/* Methods */
	
	/**
	 * Creates a new order.
	 * @param firstname the first name on the order
	 * @param lastname the last name on the order
	 * @param phone the phone number on the order
	 * @param status the status of the order
	 * @param paymentStatus the status of payment of the order
	 * @param delivery the delivery associated with the order
	 * @param createdBy the employee who created the order
	 * @return the new order
	 * @throws ErrorBean if the input data are not correct
	 */
	public OrderBean create (String firstname, String lastname, String phone, String status,
			String paymentStatus, String delivery, EmployeeAccountBean createdBy) throws ErrorBean {
		//get the patron info
		PatronAccountBean patron = new PatronAccountBean(0, firstname, lastname, phone);
		List<PatronAccountBean> list = pab.search(patron);
		if (list != null && list.size() > 0)
			patron = list.get(0);
		else {
			pab.persist(patron);
			patron = pab.search(patron).get(0);
		}
		
		OrderBean order = new OrderBean();
		
		order.setOrderPlaced(Calendar.getInstance());
		order.setOrderStatus(status);
		order.setPaymentStatus(paymentStatus);
		order.setPatron(patron);
		order.setCreatedBy(createdBy);
		
		//create a new delivery if needed
		if (delivery.equals("1")) {
			DeliveryBean del = new DeliveryBean(0);
			del.setFirstname(firstname);
			del.setLastname(lastname);
			del.setPhone(phone);
			db.persist(del);
			int delID = db.getNewId();
			del.setId(delID);
			order.setDelivery(del);
		}
		
		//get GST and PST
		List<String> taxList = cfb.listAll("tax");
		order.setGstAmount(checkGST(taxList.get(0)));
		order.setPstAmount(checkPST(taxList.get(1)));
		
		ob.persist(order);
		
		//get the newly created order's ID
		order.setId(ob.getNewOrderID());
		return order;
	}
	
	/**
	 * Searches for orders which match the search criteria.
	 * @param id the ID to search for (0 excludes this field when searching)
	 * @param firstname the first name to search for (<code>""</code> excludes this field when searching)
	 * @param lastname the last name to search for (<code>""</code> excludes this field when searching)
	 * @param phone the phone number to search for (<code>""</code> excludes this field when searching)
	 * @param status the status to search for (<code>""</code> excludes this field when searching)
	 * @param paymentStatus the payment status to search for (<code>""</code> excludes this field when searching)
	 * @return a <code>List</code> of results
	 * @throws ErrorBean if the input data are not correct
	 */
	public List<OrderBean> search(String id, String firstname, String lastname, String phone, 
			String status, String paymentStatus) throws ErrorBean {
		List<OrderBean> orderList = new ArrayList<OrderBean>();
		OrderBean searchBean = new OrderBean();
		// Search by id
		int idInt = 0;
		try {
			if (id != null && !id.equals(""))
				idInt = Integer.parseInt(id);
		} catch (NumberFormatException e) {
			throw new ErrorBean(ORDER_ID_INVALID, e.getMessage());
		}
		
		if (idInt > 0) {
			searchBean.setId(idInt);
			orderList = ob.search(searchBean);
		}
		else {
			// search for a patron
			PatronAccountBean patron = new PatronAccountBean();
			patron.setFirstname(firstname);
			patron.setLastname(lastname);
			patron.setPhone(phone);
			List<PatronAccountBean> list = pab.search(patron);
			
			
			// search for an order
			for (int i = 0; i < list.size(); i++) {
				searchBean = new OrderBean();
				searchBean.setPatron(list.get(i));
				searchBean.setOrderStatus(status);
				searchBean.setPaymentStatus(paymentStatus);
				orderList.addAll(ob.search(searchBean));
			}
		}
		return orderList;
		
	}
	
	/**
	 * Updates an order.
	 * @param id the ID of the order
	 * @param firstname the first name on the order
	 * @param lastname the last name on the order
	 * @param phone the phone number on the order
	 * @param orderStatus the status of the order
	 * @param paymentStatus the status of payment of the order
	 * @param delivery the delivery associated with the order
	 * @throws ErrorBean if the input data are not correct
	 */
	public void update (String id, String firstname, String lastname, String phone,
			String orderStatus,String paymentStatus, String delivery) throws ErrorBean {
		OrderBean order = new OrderBean(checkOrderId(id));
		
		// check if the status is done and if so, abort the update
		OrderBean old = ob.search(order).get(0);
		if (old.getOrderStatus().equalsIgnoreCase("Done"))
			throwError(
				ORDER_FINALIZED, 
				OrderControl.class.getName());
		
		// update the patron information
		int patronId = old.getPatron().getId();
		PatronAccountBean patron = new PatronAccountBean(patronId, firstname, lastname, phone);
		System.out.println("patron: "+ patron);
		pab.persist(patron);
		
		
		// update the order information
		order.setPatron(patron);
		order.setCreatedBy(old.getCreatedBy());
		order.setOrderStatus(orderStatus);
		order.setPaymentStatus(paymentStatus);
		// take care of delivery
		boolean needDelivery = delivery.equalsIgnoreCase("1");
		DeliveryBean del = old.getDelivery();
		boolean removeDel = false;
		if (needDelivery && del == null) {
			// create a new delivery
			del = new DeliveryBean(0);
			del.setFirstname(firstname);
			del.setLastname(lastname);
			del.setPhone(phone);
			db.persist(del);
			order.setDelivery(new DeliveryBean(db.getNewId()));
		}
		else if (!needDelivery && del != null) {
			// set the delivery to null
			order.setDelivery(null);
			removeDel = true;
		}
		else
			order.setDelivery(old.getDelivery());
		order.setOrderPlaced(old.getOrderPlaced());
		order.setOrderItemList(order.getOrderItemList());
		order.setPstAmount(old.getPstAmount());
		order.setGstAmount(old.getGstAmount());
		if (paymentStatus.equalsIgnoreCase("Paid"))
			order.setBalancePaid(order.getTotal());
		else
			order.setBalancePaid(old.getBalancePaid());
		ob.persist(order);
		
		if (removeDel)
			db.remove(del);
	}
	
	/**
	 * Deletes an order.
	 * @param orderID the ID of the order
	 * @throws ErrorBean if the input data are not correct
	 */
	public void delete (String orderID) throws ErrorBean {
		ob.remove(new OrderBean(checkOrderId(orderID)));
	}
	
	/**
	 * Creates an order.
	 * @param orderContents a <code>String</code> containing the order contents
	 * @return the new order
	 * @throws ErrorBean if the input data are not correct
	 */
	public OrderBean createOrder (String orderContents) throws ErrorBean {
		StringTokenizer st = new StringTokenizer(orderContents, ",");
		OrderBean order = new OrderBean();
		while (st.hasMoreTokens()) {
			String token = st.nextToken();
			try {
				StringTokenizer st2 = new StringTokenizer(token, ";");
				int id = Integer.parseInt(st2.nextToken());
				int quantity = Integer.parseInt(st2.nextToken());
				List<MenuItemBean> beanList = mib.search(new MenuItemBean(id));
				if (beanList.size() != 1)
					throwError(
						ORDERITEM_INVALID,
						token,
						this);
				
				OrderItemBean bean = new OrderItemBean(beanList.get(0), quantity);
				order.addOrderItem(bean);
			} catch (Exception e) {
				throwError(
					ORDERITEM_INVALID,
					token,
					this);
			}
		}
		return order;
	}
	
	/**
	 * Lists all orders.
	 * @return a <code>List</code> of results
	 * @throws ErrorBean if there is an error retrieving the data
	 */
	public List<OrderBean> listAll () throws ErrorBean {
		return ob.listAll();
	}
	
	/**
	 * Lists all order statuses.
	 * @return a <code>List</code> of results
	 * @throws ErrorBean if there is an error retrieving the data
	 */
	public List<String> listOrderStatus() throws ErrorBean {
		return cfb.listAll("orderStatus");
	}
	
	/**
	 * Lists all payment statuses.
	 * @return a <code>List</code> of results
	 * @throws ErrorBean if there is an error retrieving the data
	 */
	public List<String> listPaymentStatus() throws ErrorBean {
		return cfb.listAll("paymentStatus");
	}
	
	/**
	 * Lists all order items in an order
	 * @param id the ID of the order
	 * @return a <code>List</code> of results
	 * @throws ErrorBean if the input data are not correct
	 */
	public List<OrderItemBean> listOrderItem (String id) throws ErrorBean {
		return ob.getOrderItemList(new OrderBean(checkOrderId(id)));
	}
	
	/**
	 * Adds a menu item to an order.
	 * @param orderId thi ID of the order
	 * @param menuItemId the ID of the menu item
	 * @throws ErrorBean if the input data are not correct
	 */
	public void addItem (String orderId, String menuItemId) throws ErrorBean {
		ob.addOrderItem(
			new OrderBean(checkOrderId(orderId)),
			new MenuItemBean(checkMenuItemId(menuItemId)));
	}
	
	/**
	 * Removes a menu item from an order.
	 * @param orderId the ID of the order
	 * @param menuItemId the ID of the menu item
	 * @throws ErrorBean if the input data are not correct
	 */
	public void removeItem (String orderId, String menuItemId) throws ErrorBean {
		ob.removeOrderItem(
			new OrderBean(checkOrderId(orderId)),
			new MenuItemBean(checkMenuItemId(menuItemId)));
	}
	
	/**
	 * Decreases the quantity of an menu item by 1 in an order. 
	 * If the quantity was previously 1, the order item is deleted.
	 * @param orderId the ID of the order
	 * @param menuItemId the ID of the menu item
	 * @throws ErrorBean if the input data are not correct
	 */
	public void decreaseItemQty (String orderId, String menuItemId) throws ErrorBean {
		ob.decreaseItemQty(
			new OrderBean(checkOrderId(orderId)),
			new MenuItemBean(checkMenuItemId(menuItemId)));
	}
	
	/* END Methods */
	
	
	/* Data Checks */
	
	private int checkOrderId (String sOrderID) throws ErrorBean {
		return checkInt(sOrderID, ORDER_ID_INVALID, this);}
	
	private int checkMenuItemId (String menuItemId) throws ErrorBean {
		return checkInt(menuItemId, MENUITEM_ID_INVALID, this);}
	
	private double checkGST (String gst) throws ErrorBean {
		return checkDouble(gst, ORDER_GSTAMOUNT_INVALID, this);}

	private double checkPST (String pst) throws ErrorBean {
		return checkDouble(pst, ORDER_PSTAMOUNT_INVALID, this);}
	
	/* END Data Checks */
	
}
